﻿#ifndef CNGRAPHI_EYE
#define CNGRAPHI_EYE


#include "./Core/Tex.hlsl"
#include "./Core/Color.hlsl"


// /////////////////////////////////////////////////////////////


// 虹膜数据结构
struct IrisData
{
	float radius; // 弧度
	float planeOffset; // 偏移
};

/*
	虹膜数据
*/
IrisData GetIrisData()
{
	IrisData data;

	#if SHADERGRAPH_PREVIEW
		data.radius = 0.0;
		data.planeOffset = 0.0;
	#else
		data.radius = 0.22;
		data.planeOffset = 0.02;
	#endif

	return data;
}



/*
	角膜折射率
*/
float CorneaIOR()
{
	#if SHADERGRAPH_PREVIEW
		return 0.0;
	#else
		return 1.4;
	#endif
}



/*
	计算顶点缩放
	( OS 空间 )
*/
void CalculateMeshScale_float(float3 posOS, out float3 Result)
{
	Result = posOS * _MeshScale;
}




/*
	计算巩膜数据
*/
void CalculateScleraData_float
(
// input
float3 posOS, float3 viewDirOS,

// output
out float3 C, // 颜色
out float3 N, // 法线
out float S  // 平滑度
)
{
	// 计算巩膜采样UV
	float2 scleraUV = posOS.xy + float2(0.5, 0.5);

	// 计算反照率
	UnityTexture2D scleraAlbedoTex = UnityBuildTexture2DStructNoScale( _ScleraAlbedoTex );
	float4 scleraAlbedo = SAMPLE_TEXTURE2D(scleraAlbedoTex.tex, scleraAlbedoTex.samplerstate, scleraAlbedoTex.GetTransformedUV(scleraUV));

	// 计算巩膜缘环
	IrisData irisData = GetIrisData(); // 虹膜数据
	float irisRadius = irisData.radius;
	float NdotV = dot(float3(0.0, 0.0, 1.0), viewDirOS);
    float scleraRadius = length(posOS.xy);
    float limbalRingFactor = scleraRadius > irisRadius ? (scleraRadius > (_ScleraLimbalRingSize + irisRadius) ? 1.0 : lerp(0.5, 1.0, (scleraRadius - irisRadius) / (_ScleraLimbalRingSize))) : 1.0;
    limbalRingFactor = pow(limbalRingFactor, _LimbalRingIntensity);
    limbalRingFactor = lerp(limbalRingFactor, pow(limbalRingFactor, _LimbalRingFade), 1.0 - NdotV);
	C = limbalRingFactor * scleraAlbedo;

	// 计算法线
	UnityTexture2D scleraNormalTex = UnityBuildTexture2DStructNoScale( _ScleraNormalTex );
	N = SampleTexNormalWithIntensity(scleraNormalTex, scleraUV, _ScleraNormalIntensity);

	// 平滑度
	S = clamp(_ScleraSmoothing, 0.0, 1.0);
}




/*
	计算虹膜数据
	此函数包含了 “角膜、瞳孔、虹膜” 的计算
*/
void CalculateIrisData_float
(
// input
float3 posOS, float3 viewDirOS, float3 corneaNormalOS,

// output
out float3 C
//out float3 N
)
{
	// 虹膜数据
	IrisData irisData = GetIrisData();

	// 计算角膜折射
    float eta = 1.0 / CorneaIOR();
    corneaNormalOS = normalize(corneaNormalOS);
    viewDirOS = -normalize(viewDirOS);
    float3 refractedViewDirectionOS = refract(viewDirOS, corneaNormalOS, eta);
    float t = -(posOS.z + irisData.planeOffset) / refractedViewDirectionOS.z;
    float3 refractedPositionOS = float3(refractedViewDirectionOS.z < 0 ? posOS.xy + refractedViewDirectionOS.xy * t: float2(1.5, 1.5), 0.0);

	// 计算虹膜采样UV
	float2 irisUV = posOS.xy / irisData.radius;
    irisUV = irisUV * 0.5 + float2(0.5, 0.5);

	// 计算虹膜缘环
	float NdotV = dot(float3(0.0, 0.0, 1.0), viewDirOS);
    float2 irisUVCentered = (irisUV - 0.5f) * 2.0f; // 将虹膜位置归一化
    float localIrisRadius = length(irisUVCentered);
    float limbalRingFactor = localIrisRadius > (1.0 - _IrisLimbalRingSize) ? lerp(0.1, 1.0, saturate(1.0 - localIrisRadius) / _IrisLimbalRingSize) : 1.0;
    limbalRingFactor = pow(limbalRingFactor, _LimbalRingIntensity);
    limbalRingFactor = lerp(limbalRingFactor, pow(limbalRingFactor, _LimbalRingFade), 1.0 - NdotV);

	// 计算瞳孔
    // 根据瞳孔的孔径，获取新的位置
    float newPupilRadius = _PupilApeture > 0.5 ? lerp(_PupilRadius, _PupilApetureMax, (_PupilApeture - 0.5) * 2.0) : lerp(_PupilApetureMin, _PupilRadius, _PupilApeture * 2.0);
    // 瞳孔内部
    float newIrisRadius = localIrisRadius < newPupilRadius ? ((_PupilRadius / newPupilRadius) * localIrisRadius) : 1.0 - ((1.0 - _PupilRadius) / (1.0 - newPupilRadius)) * (1.0 - localIrisRadius);
    float2 animatedIrisUV = irisUVCentered / localIrisRadius * newIrisRadius;
    animatedIrisUV = (animatedIrisUV * 0.5 + float2(0.5, 0.5)); // 将计算结果转回【0-1】

	// 加上虹膜uv偏移得到最终的虹膜采样UV
	float2 irisSampleUV = animatedIrisUV + _IrisOffset;

	// 计算虹膜反照率
	UnityTexture2D irisAlbedoTex = UnityBuildTexture2DStructNoScale( _IrisAlbedoTex );
	float4 irisAlbedo = SAMPLE_TEXTURE2D(irisAlbedoTex.tex, irisAlbedoTex.samplerstate, irisAlbedoTex.GetTransformedUV(irisSampleUV));
	
	// 反照率执行颜色变换（使用颜色变换器对反照率的rgb进行调整，实现颜色多态性）
	float3 irisAlbedoRGB = irisAlbedo.rgb;
	irisAlbedoRGB = Hue(irisAlbedoRGB, _IrisHue); // 色相
	irisAlbedoRGB = Brightness(irisAlbedoRGB, _IrisBrightness); // 明亮度 
	irisAlbedoRGB = Saturation(irisAlbedoRGB, _IrisSaturation); // 饱和度
	irisAlbedoRGB = Contrast(irisAlbedoRGB, _IrisContrast); // 对比度
	irisAlbedo.rgb = irisAlbedoRGB;

	// 采样uv范围限定
	float4 irisClamp = (irisSampleUV.x < 0.0 || irisSampleUV.y < 0.0 || irisSampleUV.x > 1.0 || irisSampleUV.y > 1.0) ? float4(1,1,1,1) : irisAlbedo;
	// 最终的虹膜颜色
	C = (irisClamp * limbalRingFactor).rgb;
	
	// 虹膜法线
	//UnityTexture2D irisNormalTex = UnityBuildTexture2DStructNoScale( _IrisNormalTex );
	//N = SampleTexNormalWithIntensity(irisNormalTex, irisSampleUV, _IrisNormalIntensity);
}




/*
	计算最终的眼球表面着色数据
*/
void CalculateFinal_float
(
// input
float3 scleraColor, float3 scleraNormal, float scleraSmooth,
float3 posOS,
float3 irisColor, /* float3 irisNormal, */

// output
out float3 BaseColor,
out float3 Normal,
out float Smooth

//out float3 IrisNormal,
//out float SurfaceMsk,
//out float corneaIOR
)
{
	// 虹膜弧度
	IrisData irisData = GetIrisData();
	float irisRadius = irisData.radius;

	// 计算混合因子
	float osRadius = length(posOS.xy);
	float innerBlendRegionRadius = irisRadius - 0.02;
    float outerBlendRegionRadius = irisRadius + 0.02;
	float blendLerpFactor = 1.0 - (osRadius - irisRadius) / (0.04);
    blendLerpFactor = pow(blendLerpFactor, 8.0);
    blendLerpFactor = 1.0 - blendLerpFactor;

	// 计算输出参数
	float surfaceMask = (osRadius > outerBlendRegionRadius) ? 0.0 : ((osRadius < irisRadius) ? 1.0 : (lerp(1.0, 0.0, blendLerpFactor)));
	BaseColor = lerp(scleraColor, irisColor, surfaceMask); // 对虹膜与巩膜颜色进行插值混合
	Normal = lerp(scleraNormal, float3(0.0, 0.0, 1.0), surfaceMask); // 高光法线
	Smooth = lerp(scleraSmooth, _CorneaSmooth, surfaceMask); // 平滑度

	// 以下参数为 HDRP 渲染管线下的计算。目前基于蓝图开发，暂时无法修改底层脚本。后续会以全手工编写方式进行计算。
	//IrisNormal = lerp(scleraNormal, irisNormal, surfaceMask); // 虹膜法线 (用于在以副法线或环境AO的光高剔除计算)
	//corneaIOR = CorneaIOR(); // 角膜折射率（用于参与 Fresnel0 及 折射 相关的计算）
	//SurfaceMsk = surfaceMask; // 表面遮罩（用于虹膜焦散Lut计算）
}


#endif 
//眼睛 | 作者：CN.Graphi